package com.example.munidingwei

import android.content.Context
import android.os.Build
import android.util.Log
import io.socket.client.IO
import io.socket.client.Socket
import io.socket.emitter.Emitter
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import java.io.IOException
import java.net.URISyntaxException
import java.util.concurrent.TimeUnit

/**
 * 后台服务器WebSocket客户端
 * 负责与Python后台服务器通信，接收定位指令和上报位置
 */
class BackendClient(private val context: Context) {
    
    companion object {
        private const val TAG = "BackendClient"
        // 默认后台服务器地址（可以通过setServerUrl修改）
        private const val DEFAULT_SERVER_URL = "https://myedu.webn.cc/backend-php/api.php"
    }
    
    private var socket: Socket? = null
    private var serverUrl = DEFAULT_SERVER_URL
    private var deviceId: String = "" // 设备ID
    private var useHttpApi = true // 是否使用HTTP API模式（默认true）
    
    // HTTP客户端
    private val httpClient = OkHttpClient.Builder()
        .connectTimeout(15, TimeUnit.SECONDS)
        .readTimeout(15, TimeUnit.SECONDS)
        .writeTimeout(15, TimeUnit.SECONDS)
        .build()
    
    private val coroutineScope = CoroutineScope(Dispatchers.IO)
    
    // JSON媒体类型
    private val JSON_MEDIA_TYPE = "application/json; charset=utf-8".toMediaType()
    
    // 连接状态
    private val _isConnected = MutableStateFlow(false)
    val isConnected: StateFlow<Boolean> = _isConnected.asStateFlow()
    
    // 位置请求回调
    private var onLocationRequestCallback: (() -> Unit)? = null
    
    /**
     * 设置服务器地址
     */
    fun setServerUrl(url: String) {
        serverUrl = url
        Log.d(TAG, "设置服务器地址: $url")
    }
    
    /**
     * 连接到后台服务器
     * 支持HTTP API和WebSocket两种模式
     */
    fun connect() {
        try {
            Log.d(TAG, "正在连接到后台服务器: $serverUrl")
            
            // 检测是否应该使用HTTP API模式
            useHttpApi = serverUrl.contains("backend-php-simple") || 
                         serverUrl.contains("api.php") ||
                         !serverUrl.contains(":5000") // Python后台默认5000端口
            
            if (useHttpApi) {
                // HTTP API模式
                Log.d(TAG, "✅ 使用HTTP API模式")
                connectHttpApi()
            } else {
                // WebSocket模式
                Log.d(TAG, "✅ 使用WebSocket模式")
                connectWebSocket()
            }
            
        } catch (e: Exception) {
            Log.e(TAG, "连接失败", e)
            _isConnected.value = false
        }
    }
    
    /**
     * 连接HTTP API后台
     */
    private fun connectHttpApi() {
        coroutineScope.launch {
            try {
                // 测试连接
                val url = "${serverUrl.trimEnd('/')}/api/devices"
                val request = Request.Builder()
                    .url(url)
                    .get()
                    .build()
                
                httpClient.newCall(request).execute().use { response ->
                    if (response.isSuccessful) {
                        _isConnected.value = true
                        Log.d(TAG, "✅ HTTP API连接成功")
                        
                        // 注册设备
                        registerDeviceHttp()
                    } else {
                        _isConnected.value = false
                        Log.e(TAG, "❌ HTTP API连接失败: ${response.code}")
                    }
                }
            } catch (e: Exception) {
                _isConnected.value = false
                Log.e(TAG, "❌ HTTP API连接异常: ${e.message}")
            }
        }
    }
    
    /**
     * 连接WebSocket后台
     */
    private fun connectWebSocket() {
        try {
            _isConnected.value = true
            Log.d(TAG, "✅ WebSocket模式（功能暂不完整）")
            return
            
            /*
            val opts = IO.Options().apply {
                reconnection = true
                reconnectionDelay = 1000
                reconnectionDelayMax = 5000
                timeout = 20000
            }
            
            socket = IO.socket(serverUrl, opts)
            
            // 连接事件
            socket?.on(Socket.EVENT_CONNECT, onConnect)
            socket?.on(Socket.EVENT_DISCONNECT, onDisconnect)
            socket?.on(Socket.EVENT_CONNECT_ERROR, onConnectError)
            
            // 自定义事件
            socket?.on("connection_response", onConnectionResponse)
            socket?.on("register_response", onRegisterResponse)
            socket?.on("request_location", onRequestLocation)
            socket?.on("location_received", onLocationReceived)
            socket?.on("pong", onPong)
            
            socket?.connect()
            */
            
        } catch (e: URISyntaxException) {
            Log.e(TAG, "服务器地址格式错误", e)
        } catch (e: Exception) {
            Log.e(TAG, "连接失败", e)
        }
    }
    
    /**
     * 断开连接
     */
    fun disconnect() {
        Log.d(TAG, "断开连接")
        _isConnected.value = false
        
        // TODO: HTTP API模式不需要断开WebSocket
        socket?.disconnect()
        socket?.off()
        socket = null
    }
    
    /**
     * 注册设备（HTTP API）
     */
    private fun registerDeviceHttp() {
        coroutineScope.launch {
            try {
                // 生成或获取固定的设备ID
                if (deviceId.isEmpty()) {
                    deviceId = getOrCreateDeviceId()
                }
                
                val json = JSONObject().apply {
                    put("device_id", deviceId)
                    put("device_name", "${Build.MANUFACTURER} ${Build.MODEL}")
                    put("device_model", Build.MODEL)
                    put("android_version", "Android ${Build.VERSION.RELEASE}")
                }
                
                val url = "${serverUrl.trimEnd('/')}/api/register"
                val body = json.toString().toRequestBody(JSON_MEDIA_TYPE)
                val request = Request.Builder()
                    .url(url)
                    .post(body)
                    .build()
                
                httpClient.newCall(request).execute().use { response ->
                    if (response.isSuccessful) {
                        val responseBody = response.body?.string()
                        Log.d(TAG, "✅ 设备注册成功: $responseBody")
                    } else {
                        Log.e(TAG, "❌ 设备注册失败: ${response.code}")
                    }
                }
            } catch (e: Exception) {
                Log.e(TAG, "❌ 设备注册异常: ${e.message}")
            }
        }
    }
    
    /**
     * 注册设备（WebSocket）
     */
    private fun registerDevice() {
        try {
            val deviceInfo = JSONObject().apply {
                put("device_name", "${Build.MANUFACTURER} ${Build.MODEL}")
                put("device_model", Build.MODEL)
                put("android_version", "Android ${Build.VERSION.RELEASE}")
            }
            
            Log.d(TAG, "注册设备: $deviceInfo")
            socket?.emit("register_device", deviceInfo)
            
        } catch (e: Exception) {
            Log.e(TAG, "设备注册失败", e)
        }
    }
    
    /**
     * 上报位置信息
     */
    fun reportLocation(locationData: LocationData) {
        Log.d(TAG, "========================================")
        Log.d(TAG, "📤 BackendClient.reportLocation() 被调用")
        Log.d(TAG, "========================================")
        
        if (!_isConnected.value) {
            Log.e(TAG, "❌ 未连接到服务器，无法上报位置")
            Log.e(TAG, "   当前连接状态: ${_isConnected.value}")
            Log.e(TAG, "   请先调用 connect() 连接服务器")
            return
        }
        
        Log.d(TAG, "✅ 服务器已连接")
        Log.d(TAG, "   使用模式: ${if (useHttpApi) "HTTP API" else "WebSocket"}")
        Log.d(TAG, "   服务器地址: $serverUrl")
        Log.d(TAG, "   设备ID: $deviceId")
        
        if (useHttpApi) {
            Log.d(TAG, "📡 使用HTTP API上报位置")
            reportLocationHttp(locationData)
        } else {
            Log.d(TAG, "📡 使用WebSocket上报位置")
            reportLocationWebSocket(locationData)
        }
    }
    
    /**
     * 上报位置信息（HTTP API）
     */
    private fun reportLocationHttp(locationData: LocationData) {
        coroutineScope.launch {
            try {
                Log.d(TAG, "----------------------------------------")
                Log.d(TAG, "🌐 开始HTTP请求上报位置")
                
                val json = JSONObject().apply {
                    put("device_id", deviceId)
                    put("latitude", locationData.latitude)
                    put("longitude", locationData.longitude)
                    put("accuracy", locationData.accuracy)
                    put("timestamp", java.text.SimpleDateFormat(
                        "yyyy-MM-dd'T'HH:mm:ss",
                        java.util.Locale.getDefault()
                    ).format(java.util.Date(locationData.timestamp)))
                    put("address", locationData.address)
                    put("location_name", locationData.locationName)
                    put("is_simulated", locationData.isSimulated)
                }
                
                val url = "${serverUrl.trimEnd('/')}/api/location"
                
                Log.d(TAG, "📋 请求详情:")
                Log.d(TAG, "   URL: $url")
                Log.d(TAG, "   Method: POST")
                Log.d(TAG, "   Content-Type: application/json")
                Log.d(TAG, "")
                Log.d(TAG, "📦 请求数据:")
                Log.d(TAG, json.toString(2)) // 格式化输出JSON
                
                val body = json.toString().toRequestBody(JSON_MEDIA_TYPE)
                val request = Request.Builder()
                    .url(url)
                    .post(body)
                    .build()
                
                Log.d(TAG, "")
                Log.d(TAG, "⏳ 发送HTTP请求...")
                
                httpClient.newCall(request).execute().use { response ->
                    Log.d(TAG, "")
                    Log.d(TAG, "📥 收到服务器响应:")
                    Log.d(TAG, "   状态码: ${response.code}")
                    Log.d(TAG, "   状态消息: ${response.message}")
                    
                    if (response.isSuccessful) {
                        val responseBody = response.body?.string()
                        Log.d(TAG, "")
                        Log.d(TAG, "✅ 位置上报成功!")
                        Log.d(TAG, "   坐标: (${locationData.latitude}, ${locationData.longitude})")
                        Log.d(TAG, "")
                        Log.d(TAG, "📄 服务器响应内容:")
                        Log.d(TAG, responseBody ?: "(空)")
                    } else {
                        val errorBody = response.body?.string()
                        Log.e(TAG, "")
                        Log.e(TAG, "❌ 位置上报失败!")
                        Log.e(TAG, "   HTTP状态码: ${response.code}")
                        Log.e(TAG, "   错误消息: ${response.message}")
                        Log.e(TAG, "")
                        Log.e(TAG, "📄 错误响应:")
                        Log.e(TAG, errorBody ?: "(空)")
                    }
                }
                
                Log.d(TAG, "----------------------------------------")
                
            } catch (e: IOException) {
                Log.e(TAG, "========================================")
                Log.e(TAG, "❌ 位置上报网络错误!")
                Log.e(TAG, "   错误类型: 网络IO异常")
                Log.e(TAG, "   错误信息: ${e.message}")
                Log.e(TAG, "")
                Log.e(TAG, "💡 可能原因:")
                Log.e(TAG, "   1. 手机网络未连接")
                Log.e(TAG, "   2. 服务器地址无法访问")
                Log.e(TAG, "   3. 网络超时")
                Log.e(TAG, "")
                Log.e(TAG, "🔍 当前服务器: $serverUrl")
                e.printStackTrace()
                Log.e(TAG, "========================================")
            } catch (e: Exception) {
                Log.e(TAG, "========================================")
                Log.e(TAG, "❌ 位置上报异常!")
                Log.e(TAG, "   错误类型: ${e.javaClass.simpleName}")
                Log.e(TAG, "   错误信息: ${e.message}")
                e.printStackTrace()
                Log.e(TAG, "========================================")
            }
        }
    }
    
    /**
     * 上报位置信息（WebSocket）
     */
    private fun reportLocationWebSocket(locationData: LocationData) {
        try {
            val locationJson = JSONObject().apply {
                put("latitude", locationData.latitude)
                put("longitude", locationData.longitude)
                put("accuracy", locationData.accuracy)
                put("timestamp", java.text.SimpleDateFormat(
                    "yyyy-MM-dd'T'HH:mm:ss",
                    java.util.Locale.getDefault()
                ).format(java.util.Date(locationData.timestamp)))
                put("address", locationData.address)
                put("location_name", locationData.locationName)
                put("is_simulated", locationData.isSimulated)
            }
            
            Log.d(TAG, "上报位置: (${locationData.latitude}, ${locationData.longitude})")
            socket?.emit("report_location", locationJson)
            
        } catch (e: Exception) {
            Log.e(TAG, "位置上报失败", e)
        }
    }
    
    /**
     * 发送心跳包
     */
    fun sendPing() {
        socket?.emit("ping")
    }
    
    /**
     * 设置位置请求回调
     */
    fun setOnLocationRequestCallback(callback: () -> Unit) {
        onLocationRequestCallback = callback
    }
    
    /**
     * 获取或创建固定的设备ID
     * 使用 Android ID + 设备型号，确保同一设备始终使用相同ID
     */
    private fun getOrCreateDeviceId(): String {
        val prefs = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
        
        // 先尝试从SharedPreferences读取
        var savedId = prefs.getString("device_id", null)
        
        if (savedId.isNullOrEmpty()) {
            // 生成新的设备ID
            val androidId = android.provider.Settings.Secure.getString(
                context.contentResolver,
                android.provider.Settings.Secure.ANDROID_ID
            ) ?: "unknown"
            
            // 使用 Android ID + 设备型号（不包含时间戳）
            savedId = "android_${Build.MODEL.replace(" ", "_")}_$androidId"
            
            // 保存到SharedPreferences
            prefs.edit().putString("device_id", savedId).apply()
            
            Log.d(TAG, "✅ 生成新设备ID: $savedId")
        } else {
            Log.d(TAG, "✅ 使用已保存的设备ID: $savedId")
        }
        
        return savedId
    }
    
    // ========== WebSocket事件监听器 ==========
    
    private val onConnect = Emitter.Listener {
        Log.d(TAG, "✅ 连接成功")
        _isConnected.value = true
        // 连接成功后立即注册设备
        registerDevice()
    }
    
    private val onDisconnect = Emitter.Listener {
        Log.d(TAG, "❌ 连接断开")
        _isConnected.value = false
    }
    
    private val onConnectError = Emitter.Listener { args ->
        Log.e(TAG, "连接错误: ${args.firstOrNull()}")
        _isConnected.value = false
    }
    
    private val onConnectionResponse = Emitter.Listener { args ->
        try {
            val data = args[0] as JSONObject
            Log.d(TAG, "收到连接响应: ${data.getString("message")}")
        } catch (e: Exception) {
            Log.e(TAG, "解析连接响应失败", e)
        }
    }
    
    private val onRegisterResponse = Emitter.Listener { args ->
        try {
            val data = args[0] as JSONObject
            val success = data.getBoolean("success")
            val message = data.getString("message")
            
            if (success) {
                Log.d(TAG, "✅ 设备注册成功: $message")
            } else {
                Log.e(TAG, "❌ 设备注册失败: $message")
            }
        } catch (e: Exception) {
            Log.e(TAG, "解析注册响应失败", e)
        }
    }
    
    private val onRequestLocation = Emitter.Listener { args ->
        try {
            val data = args[0] as JSONObject
            val message = data.optString("message", "")
            
            Log.d(TAG, "📍 收到定位请求: $message")
            
            // 触发位置请求回调
            onLocationRequestCallback?.invoke()
            
        } catch (e: Exception) {
            Log.e(TAG, "解析定位请求失败", e)
        }
    }
    
    private val onLocationReceived = Emitter.Listener { args ->
        try {
            val data = args[0] as JSONObject
            val message = data.optString("message", "")
            Log.d(TAG, "✅ 位置已被服务器接收: $message")
        } catch (e: Exception) {
            Log.e(TAG, "解析位置接收确认失败", e)
        }
    }
    
    private val onPong = Emitter.Listener { args ->
        try {
            val data = args[0] as JSONObject
            Log.d(TAG, "🏓 收到心跳响应")
        } catch (e: Exception) {
            Log.e(TAG, "解析心跳响应失败", e)
        }
    }
    
    /**
     * 检查是否已连接
     */
    fun isConnectedToServer(): Boolean {
        return _isConnected.value && socket?.connected() == true
    }
}


